package com.fullstack.landscape.editor.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.fullstack.landscape.editor.controller.vo.ModuleVO;
import com.fullstack.landscape.editor.controller.vo.SpotListVO;
import com.fullstack.landscape.editor.dao.entity.ModuleEntity;
import com.fullstack.landscape.editor.dao.mapper.ModuleMapper;
import com.fullstack.landscape.editor.service.AttachmentService;
import com.fullstack.landscape.editor.service.ModuleService;
import com.fullstack.landscape.editor.service.SpotService;
import com.google.common.collect.Lists;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.*;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import static org.slf4j.LoggerFactory.getLogger;

/**
 * @author leven.chen
 * @project landscape-editor
 * @date 2019/4/9 20:11
 * @apiNote
 */
@Service
public class ModuleServiceImpl implements ModuleService {

    /**
     * logger
     */
    private static final Logger log = getLogger(ModuleServiceImpl.class);
    /**
     * 匹配字符串中的img标签
     */
    private static final Pattern P_IMAGE = Pattern.compile("<(img|IMG)(.*?)(>|></img>|/>)");
    /**
     * 匹配图片的地址
     */
    private static final Pattern P_SRC_TEXT = Pattern.compile("(src|SRC)=([\"'])(.*?)([\"'])");


    private final ModuleMapper moduleMapper;

    private final AttachmentService attachmentService;

    private final SpotService spotService;

    public ModuleServiceImpl(ModuleMapper moduleMapper, AttachmentService attachmentService, SpotService spotService) {
        this.moduleMapper = moduleMapper;
        this.attachmentService = attachmentService;
        this.spotService = spotService;
    }


    @Override
    public List<ModuleVO> getList() {
        List<ModuleEntity> list = this.getModuleList();
        return list.stream().map(item -> {
            ModuleVO vo = new ModuleVO();
            BeanUtils.copyProperties(item, vo);
            return vo;
        }).collect(Collectors.toList());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(int id) {
        moduleMapper.delete(id);
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void save(String name, String avatarPath) {
        if (StringUtils.isBlank(name)) {
            throw new RuntimeException("模块名称不能为空");
        }

        ModuleEntity entity = new ModuleEntity();
        entity.setName(name);
        if (StringUtils.isNoneBlank(avatarPath)) {

            entity.setAvatarPath(avatarPath);
        }
        moduleMapper.save(entity);

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void update(int id, String name, String avatarPath) {
        ModuleEntity entity = new ModuleEntity();
        entity.setId(id);
        if (StringUtils.isNoneBlank(name)) {
            entity.setName(name);
        }
        if (StringUtils.isNoneBlank(avatarPath)) {
            entity.setAvatarPath(avatarPath);
        }
        moduleMapper.updateSelectiveById(entity);
    }

    @Override
    public File export() {

        String workspacePath = attachmentService.getWorkspace();
        String exportDirPath = workspacePath + File.separator + "export";
        File exportDir = new File(exportDirPath);
        FileUtil.del(exportDirPath);
        if (!FileUtil.exist(exportDir)) {
            FileUtil.mkdir(exportDir);
        }
        //生成data.json
        JSONConfig config = new JSONConfig();
        config.setIgnoreNullValue(false);
        JSONObject data = new JSONObject(16, config);
        List<ModuleVO> list = this.getList();
        List<String> needAttachmentIdList = Lists.newArrayList();
        data.put("moduleList", list);
        for (ModuleVO vo : list) {
            Integer moduleId = vo.getId();
            String moduleAvatarPath = vo.getAvatarPath();
            List<SpotListVO> spotList = spotService.getSpotList(moduleId);
            String key = "M-" + moduleId;
            data.put(key, spotList);
            addAttachmentId(needAttachmentIdList, moduleAvatarPath, spotList);
        }
        String dataJsonPath = exportDir + File.separator + "data.json";
        OutputStream dataJsonFile;
        try {
            dataJsonFile = new FileOutputStream(dataJsonPath);
            IOUtils.write(data.toString(), dataJsonFile, Charset.forName("UTF-8"));
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("配置数据导出失败");
        }

        //copy 需导出的附件到新的文件夹
        for (String attachmentId : needAttachmentIdList) {
            String storeDir = attachmentService.getStoreDir();
            File attachFile = new File(storeDir + File.separator + attachmentId);
            FileUtil.copyFilesFromDir(attachFile, exportDir, true);
        }

        //打包zip文件
        try {
            File tempFile = File.createTempFile("landscape", "export");
            FileOutputStream fos = new FileOutputStream(tempFile);
            ZipOutputStream zipOut = new ZipOutputStream(fos);
            zipFile(exportDir, exportDir.getName(), zipOut);
            zipOut.close();
            fos.close();
            return tempFile;
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("数据压缩失败");
        }

    }

    private void addAttachmentId(List<String> needAttachmentIdList, String moduleAvatarPath, List<SpotListVO> spotList) {
        //添加附件ID
        if (StringUtils.isNoneBlank(moduleAvatarPath)) {
            needAttachmentIdList.add(moduleAvatarPath);
        }
        if (CollectionUtil.isNotEmpty(spotList)) {
            for (SpotListVO spotVO : spotList) {
                String spotAvatarPath = spotVO.getAvatarPath();
                String spotVidePath = spotVO.getVideoPath();
                String content = spotVO.getContent();
                if (StringUtils.isNoneBlank(spotAvatarPath)) {
                    needAttachmentIdList.add(spotAvatarPath);
                }
                if (StringUtils.isNoneBlank(spotVidePath)) {
                    needAttachmentIdList.add(spotVidePath);
                }
                if (StringUtils.isNoneBlank(content)) {
                    List<String> attachmentIdList = this.getAttachmentIdFromContent(content);
                    needAttachmentIdList.addAll(attachmentIdList);
                }

            }
        }
    }

    private List<String> getAttachmentIdFromContent(String content) {
        log.debug("提取content中的附件");
        Matcher matcher = P_IMAGE.matcher(content);
        boolean hasPic = matcher.find();
        List<String> contentAttachIdList = Lists.newArrayList();
        //判断是否含有图片
        if (hasPic) {
            //如果含有图片，那么持续进行查找，直到匹配不到
            while (hasPic) {
                //获取第二个分组的内容，也就是 (.*?)匹配到的
                String group = matcher.group(2);
                Matcher matcher2 = P_SRC_TEXT.matcher(group);
                if (matcher2.find()) {
                    //把获取到的图片地址添加到列表中
                    //src="/api/attachment/adeaced916db402a8e94744b8d209b40.jpg"
                    String srcValue = matcher2.group(3);
                    if (srcValue.startsWith("/api/attachment")) {
                        String[] srcPaths = srcValue.split("/");
                        int len = srcPaths.length;
                        if (len > 2) {
                            contentAttachIdList.add(srcPaths[len - 1]);
                        }
                    }
                }
                //判断是否还有img标签
                hasPic = matcher.find();
            }

        }

        return contentAttachIdList;
    }


    private static void zipFile(File fileToZip, String fileName, ZipOutputStream zipOut) throws IOException {
        if (fileToZip.isHidden()) {
            return;
        }
        if (fileToZip.isDirectory()) {
            if (fileName.endsWith("/")) {
                zipOut.putNextEntry(new ZipEntry(fileName));
                zipOut.closeEntry();
            } else {
                zipOut.putNextEntry(new ZipEntry(fileName + "/"));
                zipOut.closeEntry();
            }

            File[] children = fileToZip.listFiles();
            if (Objects.nonNull(children)) {
                for (File childFile : children) {
                    zipFile(childFile, fileName + "/" + childFile.getName(), zipOut);
                }
            }
            return;
        }

        FileInputStream fis = new FileInputStream(fileToZip);
        ZipEntry zipEntry = new ZipEntry(fileName);
        zipOut.putNextEntry(zipEntry);
        byte[] bytes = new byte[1024];
        int length;
        while ((length = fis.read(bytes)) >= 0) {
            zipOut.write(bytes, 0, length);
        }
        fis.close();
    }

    private List<ModuleEntity> getModuleList() {
        // List<ModuleEntity> list = moduleMapper.getList();

        String vales = "[{\"id\":1,\"name\":\"额伊特湖 (大天鹅湖)\"},{\"id\":2,\"name\":\"阿布什格湖\"},{\"id\":3,\"name\":\"布日呼图湖\"},{\"id\":4,\"name\":\"巴格达布苏湖\"},{\"id\":5,\"name\":\"吉格尔其库湖\"},{\"id\":6,\"name\":\"阿德格伊克尔湖\"},{\"id\":7,\"name\":\"额肯伊克尔湖\"},{\"id\":8,\"name\":\"天鹅湖景区沙金园度假村\"},{\"id\":9,\"name\":\"查干布湖\"},{\"id\":10,\"name\":\"乌库太湖\"},{\"id\":11,\"name\":\"霍林高勒湖\"},{\"id\":12,\"name\":\"通格图湖\"},{\"id\":13,\"name\":\"温布中转站\"},{\"id\":14,\"name\":\"天鹅湖游客接待中心\"},{\"id\":15,\"name\":\"天鹅湖蒙古大营\"},{\"id\":16,\"name\":\"与沙共舞\"},{\"id\":17,\"name\":\"巴彦浩特镇\"}]";

        JSONArray jsonArray = JSONUtil.parseArray(vales);
        List<ModuleEntity> moduleEntityList = jsonArray.toList(ModuleEntity.class);
        return moduleEntityList;
    }


}
